﻿package racingGame.models 
{
	import away3d.core.base.Face;
	import away3d.core.base.UV;
	import away3d.core.base.Vertex;
	import away3d.core.math.Number3D;
	import away3d.materials.ITriangleMaterial;
	/**
	 * ...
	 * @author Jorge Miranda
	 */
	public class TrackSegment
	{
		/**** Private Static Constants ****/
		
		private static const GUARDRAIL_OFFSET_Y		:Number = 2;
		
		
		/**** Private Variables ****/
		
		private var _face0		:Face;
		private var _face1		:Face;
		private var _faces		:Vector.<Face>;
		private var _v0			:Vertex;
		private var _v1			:Vertex;
		private var _v2			:Vertex;
		private var _v3			:Vertex;
		private var _g0			:Vertex;
		private var _g1			:Vertex;
		private var _g2			:Vertex;
		private var _g3			:Vertex;
		private var _road_width		:Number;
		private var _guardrail_width:Number;
		private var _road_material	:ITriangleMaterial;
		private var _guardrail_material	:ITriangleMaterial;
		private var _start		:Number3D;
		private var _end		:Number3D;
		private var S:Number3D;
		
		/**** Public Properties ****/	
		
		public function get faces():Vector.<Face> { return _faces; }
		
		public function get length():Number { return S.modulo; }
		
		public function get v0():Number3D { return _v0.position; }		
		public function set v0(value:Number3D):void 
		{	
			_v0.setValue(value.x, value.y, value.z);
			moveGuardRailVertex(_g0, _v0, _start);
		}		
		public function get v1():Number3D { return _v1.position; }		
		public function set v1(value:Number3D):void 
		{	
			_v1.setValue(value.x, value.y, value.z);			
			moveGuardRailVertex(_g1, _v1, _end);
		}
		public function get v2():Number3D { return _v2.position; }		
		public function set v2(value:Number3D):void 
		{	
			_v2.setValue(value.x, value.y, value.z);
			moveGuardRailVertex(_g2, _v2, _start);
		}		
		public function get v3():Number3D { return _v3.position; }		
		public function set v3(value:Number3D):void 
		{	
			_v3.setValue(value.x, value.y, value.z);
			moveGuardRailVertex(_g3, _v3, _end);
		}	
		
		public function get start():Number3D { return _start; }
		
		public function get end():Number3D { return _end; }
		
		
		/**** Public Methods ****/
		
		/*
		 * Constructor
		 */
		
		public function TrackSegment(A:Number3D, B:Number3D, width:Number, road_material:ITriangleMaterial = null, guardrail_material:ITriangleMaterial = null,textureTileStart:Number = 0, textureDefaultLenght:Number = 10 ):void
		{
			_start = A;
			_end = B;
			
			_road_width = width;
			_guardrail_width = width * .25;
			_road_material = road_material
			_guardrail_material = guardrail_material
			_faces = new Vector.<Face>();
			
			// Translate the segment to the origin.
			// S = B - A
			S = new Number3D();
			S.sub(B, A);
			
			// Get the orthogonal point.
			/*
			 *   S	|
			 *		|
			 *		|
			 *		|  r/2->
			 *	 O	------- C
			 */
			
			var guardrailNormal :Number3D = new Number3D();
			var C:Number3D = new Number3D();
			var r:Number = _road_width / 2;
			
			C.x = S.z;
			C.z = -S.x
			
			guardrailNormal.scale(C, _guardrail_width / C.modulo);		
			C.scale(C, r / C.modulo);			
			
			/*	
			 *   v1	----B---- v3
			 *   	|\		|
			 *		| \		|
			 *		|  \	|
			 *		|   \	|
			 *		|    \	|	 
			 *		|     \	|
			 *		|      \|
			 *	 v0	----A---C v2
			 *		 r->
			 */
			
			
			
			// Road vertexes
			_v0 = new Vertex(A.x - C.x, A.y - C.y, A.z - C.z);		
			_v1 = new Vertex(B.x - C.x, B.y - C.y, B.z - C.z);
			_v2 = new Vertex(A.x + C.x, A.y + C.y, A.z + C.z);		
			_v3 = new Vertex(B.x + C.x, B.y + C.y, B.z + C.z);
			
			// Guardrail vertexes			
			_g0 = new Vertex(_v0.x - guardrailNormal.x, _v0.y - guardrailNormal.y + GUARDRAIL_OFFSET_Y, _v0.z - guardrailNormal.z);		
			_g1 = new Vertex(_v1.x - guardrailNormal.x, _v1.y - guardrailNormal.y + GUARDRAIL_OFFSET_Y, _v1.z - guardrailNormal.z);		
			_g2 = new Vertex(_v2.x + guardrailNormal.x, _v2.y + guardrailNormal.y + GUARDRAIL_OFFSET_Y, _v2.z + guardrailNormal.z);		
			_g3 = new Vertex(_v3.x + guardrailNormal.x, _v3.y + guardrailNormal.y + GUARDRAIL_OFFSET_Y, _v3.z + guardrailNormal.z);		
			
			var V0:Number = textureTileStart;
			var V1:Number = textureTileStart + (S.modulo / textureDefaultLenght);
			
			// Road faces
			_face0 = new Face(_v0, _v1, _v2, _road_material, new UV(1, V0), new UV(1, V1), new UV(0, V0));
			_face1 = new Face(_v1, _v3, _v2, _road_material, new UV(1, V1), new UV(0, V1), new UV(0, V0));
			
			_faces.push(_face0);
			_faces.push(_face1);
			
			// Guardrail faces
			var grFace0 :Face = new Face(_g0, _g1, _v0, _guardrail_material, new UV(1, V0), new UV(1, V1), new UV(0, V0));
			var grFace1 :Face = new Face(_g1, _v1, _v0, _guardrail_material, new UV(1, V1), new UV(0, V1), new UV(0, V0));
			
			var grFace2 :Face = new Face(_g2, _g3, _v2, _guardrail_material, new UV(1, V0), new UV(1, V1), new UV(0, V0));
			var grFace3 :Face = new Face(_g3, _v3, _v2, _guardrail_material, new UV(1, V1), new UV(0, V1), new UV(0, V0));
			
			_faces.push(grFace0);
			_faces.push(grFace1);
			_faces.push(grFace2);
			_faces.push(grFace3);
			
		}
		
		
		/**** Private Methods ****/
		
		private function moveGuardRailVertex(gV:Vertex, rV:Vertex, ref:Number3D):void
		{
			var guardrailNormal :Number3D = new Number3D();		
			guardrailNormal.sub(rV.position, ref);
			guardrailNormal.scale(guardrailNormal, _guardrail_width / guardrailNormal.modulo);
			gV.setValue(rV.x + guardrailNormal.x, rV.y + guardrailNormal.y + GUARDRAIL_OFFSET_Y, rV.z + guardrailNormal.z);
		}
	}

}